package tp1POO.Persistencia;

import java.util.Arrays;
import java.util.Iterator;
import java.util.Vector;

import org.apache.commons.collections.MultiHashMap;
import org.apache.commons.collections.MultiMap;

import tp1POO.Modelo.Cliente;
import tp1POO.Modelo.Funcionario;
import tp1POO.Modelo.Locacao;
import tp1POO.Modelo.Motorista;
import tp1POO.Modelo.ObjetoPOO;
import tp1POO.Modelo.Pessoa;
import tp1POO.Modelo.Tipo;
import tp1POO.Modelo.Veiculo;

public class GerenciadorObjetos {

	/**
	 * Construtor padrão
	 */
	private GerenciadorObjetos() {
		objetos = new Vector<ObjetoPOO>();
		setTipofabrica(FactoryType.Banco_de_Dados);
	}
	/**
	 * Carrega os dados do banco de dados
	 */
	public void CargaInicial() {
		//objeto.putAll(Veiculo.class, Persistencia.obterInstancia().listar(new Locacao(new Veiculo(""), new Cliente())));
	}
	/**
	 * Obtem a instancia do Gerenciador (Singleton)
	 */
	public static GerenciadorObjetos obterInstancia() {
		if (instancia == null)
			instancia = new GerenciadorObjetos();
		return instancia;
	}
	/**
	 * Atualiza o objeto no vetor e persiste
	 * @param parObj ObjetoPOO a ser salvo
	 * @return se o objeto foi persistido corretamente
	 */
	public boolean salvarObj(ObjetoPOO parObj) {
		adicionarObjeto(parObj);
		return Persistencia.obterInstancia().salvar(parObj);
	}
	/**
	 * Atualiza o objeto no vetor e persiste
	 * @param parObj ObjetoPOO a ser salvo
	 * @return se o objeto foi persistido corretamente
	 */
	public boolean apagarObj(ObjetoPOO parObj) {
		boolean res = Persistencia.obterInstancia().apagar(parObj);
		if (res) {removerObjeto(parObj);}
		return res;
	}
	/**
	 * Obtem um objeto especifico determinado pelo seu identificador
	 * @param parObj ObjetoPOO a se obter
	 * @return objeto obtido
	 */
	public ObjetoPOO obterObj(ObjetoPOO parObj) {
		ObjetoPOO obj = carregarObjeto(parObj);
		//Se não está no respectivo vetor, deve ser obtido nos arquivos
		if (obj == null) {
			obj = Persistencia.obterInstancia().encontrar(parObj);
			if (obj != null)
				adicionarObjeto(obj);
		}
		//Retorna o obj
		return obj;
	}
	/**
	 * Salva um array de objetos
	 * @param objetoPOOs Array de objetos a ser persistido
	 * @return se os objetos foram persistidos
	 */
	public boolean salvarObjs(ObjetoPOO[] objetoPOOs) {
		boolean retorno = false;
		for (int i=0; i<objetoPOOs.length; i++)
			retorno &= salvarObj(objetoPOOs[i]);
		return retorno;
	}
	/**
	 * Obtem todos objetos do tipo especificado
	 * @param parObj Classe dos objetos a se obterem
	 * @return um vetor de objetos
	 */
	public Vector<ObjetoPOO> obterObjs(ObjetoPOO parObj) {
		Vector<ObjetoPOO> vet = new Vector<ObjetoPOO>(Arrays.asList(Persistencia.obterInstancia().listar(parObj).toArray(new ObjetoPOO[0])));
		
		Iterator<ObjetoPOO> it = vet.iterator();
		while (it.hasNext()) {
			adicionarObjeto(it.next());
		}

		return vet;
	}
	/**
	 * Adiciona objetos ao vetor de objetos local
	 * @param parObj Objeto a ser inserido no vetor
	 */
	protected void adicionarObjeto(ObjetoPOO parObj) {
		if (objetos.contains(parObj)) {
			removerObjeto(parObj);
		}
		objetos.add(parObj);
	}
	/**
	 * Remove objeto do vetor
	 * @param parObj ObjetoPOO a ser inserido
	 */
	protected void removerObjeto(ObjetoPOO parObj) {
		objetos.remove(parObj);
	}
	
	protected ObjetoPOO carregarObjeto(ObjetoPOO parObj) {
		ObjetoPOO obj = null;
		if (objetos.contains(parObj))
		{
			Iterator<ObjetoPOO> it = objetos.iterator();
			while (it.hasNext()) {
				if ((obj = it.next()).getIdentifier() == parObj.getIdentifier())
					break;
				else
					obj = null;
			}
		}

		return obj;
	}
	/**
	 * Ajusta o tipo de fabrica DAO a ser usado
	 * @param tipofabrica O tipo de fabrica DAO a ajustar, escolhida na GUI
	 */
	public void setTipofabrica(FactoryType tipofabrica) {
		this.tipofabrica = tipofabrica;
		Persistencia.obterInstancia().setFabrica(this.tipofabrica);
	}

	// Atributos
	private Vector<ObjetoPOO> objetos;
	private FactoryType tipofabrica;
	private static GerenciadorObjetos instancia;
}